﻿import simpy
from simpy import AllOf

from osc02.domain.activities.Assembling import Assembling


class AssemblingGrouted(Assembling):
    def __init__(self, name, duration=None, lag=0,
                 duration_likely=20,
                 duration_low=10, duration_high=45,
                 completion_event=None,
                 worker_skill='1', worker_num=0,
                 crane_type=None,
                 component=None
                 ):
        super().__init__(name, duration, lag, duration_likely, duration_low, duration_high, completion_event,
                         worker_skill, worker_num)
        self.crane_type = crane_type
        self.component = component
        self.suspended = False  # the

    def __repr__(self):
        return super().__repr__() \
               + 'component=' + str(self.component) + ', '

    def act(self):
        # Erection‘s prerequisites
        prerequisite_event = set()
        # prerequisite of predecessor completion
        for predecessor in self.incoming_nodes:
            prerequisite_event.add(predecessor.completion_event)

        # prerequisite of component delivery completion
        prerequisite_event.add(self.component_delivered_event)
        # wait for all predecessors completion
        yield AllOf(self.construction_site.env, prerequisite_event)

        # put down the actual erection start time.
        self.act_erection_start = round(self.construction_site.env.now, 2)
        # print('request crn---------')
        # print('items=', self.construction_site.crane.items)
        crane = yield self.construction_site.crane.get(self, 'REQ CRN',
                                                       lambda item: self.crane_type in item.source_type)
        # print('crane=', crane, 'after get, items=', self.construction_site.crane.items)
        assembly_worker_team = \
            yield self.construction_site.worker_teams.get(self, 'REQ WKR',
                                                          lambda item: self.worker_skill in item.source_type)

        # print(self.construction_site.env.now, self.name, 'got crn')
        # duration = self.get_stochastic_duration()
        # self.act_duration = round(duration, 2)

        # yield self.construction_site.env.timeout(self.act_duration)
        duration = self.act_duration
        # duration being not 0 means the process is suspended
        while duration:
            try:
                start = self.construction_site.env.now
                yield self.construction_site.env.timeout(duration)
                duration = 0
            except simpy.Interrupt:  # is interrupted
                self.suspended = True
                # the left time to complete the installation
                duration -= self.construction_site.env.now - start
                # it takes 2 hours to repair
                yield self.construction_site.env.timeout(2)
                # the machine is repaired and continue the installation
                self.suspended = False

        # release crane
        yield self.construction_site.crane.put(self, 'RLS CRN', crane)
        # release worker team
        yield self.construction_site.worker_teams.put(self,
                                                      'RLS WKR', assembly_worker_team)

        self.completion_event.succeed()

    # def get_stochastic_duration(activity):
    #     if global_var.get_value('STOCHASTIC_MODE'):
    #         duration = random.triangular(activity.duration_low, activity.duration, activity.duration_high)
    #     else:
    #         duration = activity.duration
    #     return duration

    # fill the storage yard with components
    def transport(self):
        # if actual delivery is earlier than schedule, take is as 0.
        # delay = max(0, self.get_delivery_delay())
        # self.act_delivery_time = self.skd_delivery_time + delay
        yield self.construction_site.env.timeout(self.act_delivery_time)
        self.component_delivered_event.succeed()
        # print('***@', self.construction_site.env.now, self.name, self.skd_delivery_time, self.act_delivery_time)

    # def get_delivery_delay(self):
    #     if global_var.get_value('STOCHASTIC_MODE'):
    #         component_delivery_delay = random.gauss(-5, 3)
    #     else:
    #         component_delivery_delay = 0
    #     return component_delivery_delay
